# coding:utf-8
import os
import logging
import argparse
from concurrent.futures import ThreadPoolExecutor
from concurrent.futures import ProcessPoolExecutor


class Logged(object):
    # 日志装饰器类，在业务代码函数的开头、结尾打日志
    def __init__(self, func):
        self._func = func

    def __call__(self, *args, **kwargs):
        logging.info('%s(...) start' % self._func.__name__)
        res = self._func(*args, **kwargs)
        logging.info('%s(...) finish' % self._func.__name__)
        return res


def procRun(item):
    try:
        return os.system(item)
    except BaseException as e:
        logging.error([item, e])
        return 1


@Logged
def procRun_for(args, cmdLines):
    # for循环串行运行
    objN = len(cmdLines)
    logging.info('Total %d command to be run' % objN)

    data = []
    for idx, item in enumerate(cmdLines, 1):
        x = procRun(item)
        data.append(x)
        logging.info('procRun %d of %d' % (idx, objN))

    return data


@Logged
def procRun_pool(args, cmdLines):
    # 利用进程池或线程池运行
    if args.poolType == 'T':
        pool = ThreadPoolExecutor(max_workers=args.workers)
    else:
        pool = ProcessPoolExecutor(max_workers=args.workers)

    objN = len(cmdLines)
    logging.info('Total %d command to be run' % objN)

    objs = [pool.submit(procRun, item) for item in cmdLines]

    logging.info('%d command has been submit' % objN)

    data = []
    for idx, obj in enumerate(objs, 1):
        x = obj.result()
        data.append(x)
        logging.info('procRun %d of %d' % (idx, objN))

    pool.shutdown()
    return data


@Logged
def mission(args):
    logging.info(vars(args))

    cmdLines = []
    try:
        with open(args.shPath, 'r', encoding='utf-8') as fid:
            cmds = fid.read()
            cmdLines = cmds.replace('\r', '').rstrip('\n').split('\n')
    except BaseException as e:
        logging.error([args.shPath, e], exc_info=True, stack_info=True)

    if args.poolType == 'T' or args.poolType == 'P':
        data = procRun_pool(args, cmdLines)
    else:
        data = procRun_for(args, cmdLines)

    logging.info({'procRun_res': data})


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--shPath',
                        help='*.sh path with one command to run per line')
    parser.add_argument('--poolType', help='T(Thread), P(Process) or N(None)')
    parser.add_argument('--workers', default=4, type=int, help='(default 4)')
    parser.add_argument('--logPath')
    args = parser.parse_args()

    L_FORMAT = '[%(asctime)s](%(created).17g) - %(levelname)s - |%(pathname)s|%(funcName)s|%(lineno)d| - %(message)s'
    D_FORMAT = '%Y-%m-%d_%H:%M:%S'
    logging.basicConfig(filename=args.logPath,
                        level=logging.DEBUG,
                        format=L_FORMAT,
                        datefmt=D_FORMAT)

    mission(args)
